import os
import re
import pandas as pd
import numpy as np

from datetime import timedelta
from util.constants import ANALYSE_START_TIME, ANALYSE_END_TIME

class Pixel:

    def __init__(self, path):
        # 初始化
        # 段落标志
        self.fileContent = None
        self.app_map_content_flag = False
        # 耗电统计
        self.averageDrain = 0
        self.qpnpRtcAlarm = 0
        self.alarmDeliveryTime = 0
        self.testTime = 0
        self.averageDrain = 0
        self.wakeupRtcAlarm = 0
        self.deliveryRtcAlarm = 0
        self.testTime = 0
        # 硬件统计
        self.cpu_count = 0
        self.radio_count = 0
        self.cpu_runtime = timedelta()
        self.cpu_start_time = 0
        self.wakeup_reason = 0
        self.wlan_ce_2 = 0
        self.hardware_wakeup = 0
        self.WIFI_AP_WAKUP = 0
        # WLAN相关
        self.package_wlan_List = pd.DataFrame(columns=['packages', 'uid', 'nums'], dtype=str)
        self.package_wlan_List['nums'] = self.package_wlan_List['nums'].astype(int)
        new_row = pd.DataFrame({'packages': 'else', 'uid': ["system"], 'nums': [0]})
        self.package_wlan_List = pd.concat([self.package_wlan_List, new_row], ignore_index=True)
        # 文件相关
        self.output_wlan_path = os.path.join("workdir", "wlan")
        self.file_name = os.path.splitext(os.path.basename(path))[0]
        self.current_app_wakeup_wlan = None
        self.parse_log(path)
        self.contentParse()

    # 将时间字符串转换为毫秒
    def parse_time(self, time_str):
        h_match = re.search(r'(?P<hour>\d+)h\d+', time_str)
        m_match = re.search(r'(?P<minute>\d+)m\d+', time_str)
        s_match = re.search(r'(?P<second>\d+)s\d+', time_str)
        ms_match = re.search(r'(?P<millisecond>\d+)ms', time_str)
        h = int(h_match.group('hour')) if h_match else 0
        m = int(m_match.group('minute')) if m_match else 0
        s = int(s_match.group('second')) if s_match else 0
        ms = int(ms_match.group('millisecond')) if ms_match else 0
        total_ms = h * 60 * 60 * 1000 + m * 60 * 1000 + s * 1000 + ms
        if total_ms == 0:
            return None
        else:
            return total_ms

    def get_time(self, time_str):
        h_match = re.search(r'(?P<hour>\d+)h\d+', time_str)
        m_match = re.search(r'(?P<minute>\d+)m\d+', time_str)
        s_match = re.search(r'(?P<second>\d+)s\d+', time_str)
        ms_match = re.search(r'(?P<millisecond>\d+)ms', time_str)

        h = int(h_match.group('hour')) if h_match else 0
        m = int(m_match.group('minute')) if m_match else 0
        s = int(s_match.group('second')) if s_match else 0
        ms = int(ms_match.group('millisecond')) if ms_match else 0

        return timedelta(hours=int(h), minutes=int(m), seconds=int(s), milliseconds=int(ms))

    def count_rtc_alarm(self, prev_timestamp, alarm_wakelock_timestamp, event):
        rtc_alarm_count = 0
        walarm_rtc_count = 0;
        if prev_timestamp is not None and '*walarm*:' in event and abs(
                prev_timestamp - alarm_wakelock_timestamp) < timedelta(
            seconds=0.5):
            rtc_alarm_count += 1

        if prev_timestamp is not None and '*alarm*:' in event and abs(
                prev_timestamp - alarm_wakelock_timestamp) < timedelta(
            seconds=0.5):
            walarm_rtc_count += 1

        return rtc_alarm_count, walarm_rtc_count;

    def count_hardware_number(self, line):
        # CPU
        if '+running' in line:
            self.cpu_count += 1
            self.cpu_start_time = self.get_time(line)
        if '627 glink-native-modem' in line:
            self.radio_count += 1
            self.hardware_wakeup += 1
        if '-running' in line and self.cpu_start_time != 0:
            self.cpu_runtime += self.get_time(line) - self.cpu_start_time
        if 'wake_reason=' in line:
            self.wakeup_reason += 1
        if 'WLAN_CE_2' in line:
            self.wlan_ce_2 += 1
            if self.current_app_wakeup_wlan is not None:
                if not (self.package_wlan_List['uid'] == self.current_app_wakeup_wlan).any():
                    tmp = self.package_wlan_List['uid'] == "system"
                else:
                    tmp = self.package_wlan_List['uid'] == self.current_app_wakeup_wlan
                self.package_wlan_List.loc[tmp, 'nums'] += 1
            self.hardware_wakeup += 1
        if "qpnp_rtc_alarm" in line:
            self.hardware_wakeup += 1

    def count_app_wlan(self, line):
        app_wlan_pattern = re.search(r'wakeupap=(.+?):.*', line)
        if app_wlan_pattern:
            self.current_app_wakeup_wlan = app_wlan_pattern.group(1)

    # 处理每一行数据
    def process_drain_line(self, line):
        screen_off_time = None
        screen_on_time = None
        charge_on_screen = None

        time = self.parse_time(line.split()[1])

        charge_search = re.search(r'charge=(\d+)', line)
        if charge_search:
            charge = int(charge_search.group(1))

        if "-screen" in line and screen_off_time is None:
            screen_off_time = time

        if "+screen" in line:
            screen_on_time = time
            charge_on_screen = charge

    def parse_log_line(self, line):
        line = line.lstrip()
        match = re.search(r"(\d+ms).*?(wake_reason=0:\"\d+ qpnp_rtc_alarm\"|\"\*walarm\*:|\"\*alarm\*:).*",
                          line)
        if match:
            return (self.get_time(line), match.group(2))

        return None

    def parse_log(self, path):
        f = open(path, encoding="ISO-8859-1")
        fileContent = f.readlines()
        f.close()
        self.content = fileContent

    def parse_timestamp(self, timestamp_str):
        m, s, ms = re.match(r"\+(\d+)m(\d+)s(\d+)ms", timestamp_str).groups()
        return timedelta(minutes=int(m), seconds=int(s), milliseconds=int(ms))

    def is_less_than_half_second(self, t1, t2):
        return abs(t1 - t2) < timedelta(seconds=0.5)

    def count_alarm_walarm(self, line):
        alarm = 0
        walarm = 0
        line = line.lstrip()
        if re.search(r':"\*walarm\*:', line):
            walarm = 1
        if re.search(r':"\*alarm\*:', line):
            alarm = 1
        return walarm, alarm

    def count_wifi_ap(self, line):
        wifi_ap_pattern = re.search(r'WiFi AP wakeups: (\d+)', line)
        if wifi_ap_pattern:
            self.WIFI_AP_WAKUP += int(wifi_ap_pattern.group(1).strip())

    def get_rtc_alarm_num(line):
        match = re.search(r'.*qpnp_rtc_alarm:.*(\d+)\s*times', line)
        if match:
            qpnp_rtc_alarm = int(match.group(1))
        return qpnp_rtc_alarm

    # 获得uid-包名关系
    def get_app_uid(self, line):
        if "PID mappings" in line and self.app_map_content_flag == False:
            self.app_map_content_flag = True
        if "Active process infos:" in line and self.app_map_content_flag == True:
            self.app_map_content_flag = False
        if (self.app_map_content_flag):
            match = re.search(r'.* \d+:(.*)/(.*)}', line)
            if match:
                if not (self.package_wlan_List['uid'] == match.group((2))).any():
                    new_row = pd.DataFrame({'packages': [match.group(1)], 'uid': [match.group(2)], 'nums': [0]})
                    self.package_wlan_List = pd.concat([self.package_wlan_List, new_row], ignore_index=True)

    def contentParse(self):
        # 初始化
        self.cpu_start_time = 0
        # 内容标志
        battery_content_flag = False
        battery_content_out_flag = False
        # wakeup标志
        wakeup_content_flag = False
        wakeup_content_out_flag = False
        # qpnp_rtc_alarm出现wakelock为walarm或者alarm次数
        walarm_rtc_count = 0
        alarm_rtc_count = 0

        # wakelock为walarm或者alarm次数
        w_count = 0
        a_count = 0
        qpnp_rtc_alarm = 0
        app_wakeup_alarm_num = 0
        prev_timestamp = None
        prev_alarm_timestamp = None

        wakeup_reason_count = 0

        # 计算真实耗电相关变量
        time = None
        charge_start = None
        charge_end = None
        charge_start_flag = True
        charge_start_time = 0

        # time pattern
        app_wakeup_num = 0
        app_wakeup = pd.DataFrame()
        for line in self.content:
            # Judge arrive batterystats paragraph
            line = line.lstrip()
            self.get_app_uid(line)
            if not battery_content_flag:
                if re.search(r"Battery History .*", line):
                    battery_content_flag = True
            # Judge out batterystats paragraph
            if (battery_content_out_flag is False) and (battery_content_flag is True):
                if re.search(r"Per-PID Stats:.*", line):
                    battery_content_out_flag = True
                    battery_content_flag = False
            # Judge arrive app status
            if (battery_content_out_flag is True) and (wakeup_content_flag is False):
                if re.search("Resource Power Manager Stats", line):
                    wakeup_content_flag = True
            # Judge out app status
            if (wakeup_content_out_flag is False) and (wakeup_content_flag is True):
                if re.search("Total cpu time reads: ", line):
                    wakeup_content_flag = False
                    wakeup_content_out_flag = True
            if battery_content_flag:
                if line.split():
                    tmp = self.parse_time(line.split()[0])
                    if tmp is not None:
                        time = tmp

                if time is not None and time < ANALYSE_START_TIME:
                    continue

                # 计算真实耗电量
                charge_search = re.search(r'charge=(\d+)', line)

                self.count_hardware_number(line)
                self.count_app_wlan(line)

                if charge_search:
                    charge = int(charge_search.group(1))
                    charge_time = time

                    # 当灭屏后，flag标志位置为true，记录第一个charge
                    if charge_start_flag and charge_time is not None and charge_time > ANALYSE_START_TIME:
                        charge_start_flag = False
                        charge_start = charge
                        charge_start_time = time

                    # 指定时间进行分析
                    if charge_time is not None and charge_time > ANALYSE_END_TIME:
                        charge_end = charge
                        charge_end_time = time
                        battery_content_flag = False
                        battery_content_out_flag = True

                # 统计qpnp_rtc_alarm
                parsed_line = self.parse_log_line(line)
                m, n = self.count_alarm_walarm(line)
                w_count += m
                a_count += n
                if parsed_line is None:
                    # 匹配actual drain
                    # Match the actual drain numbers and calculate the average
                    drain_match = re.search(r'actual drain: (\d+\.?\d*)-(\d+\.?\d*)', line)
                    if drain_match:
                        num1 = float(drain_match.group(1))
                        num2 = float(drain_match.group(2))
                        atc_drain = (num1 + num2) / 2

                    # Match the durations
                    duration_matches = re.search(r'idle:.*duration: ([\dhms\. ]+)', line)
                    if duration_matches:
                        duration = duration_matches.group(1)
                    continue

                # 匹配由rtc_alarm导致的唤醒
                timestamp, event = parsed_line
                if '*walarm*:' in event or '*alarm*:' in event:
                    prev_alarm_timestamp = timestamp
                if '546 qpnp_rtc_alarm' in event:
                    qpnp_rtc_alarm += 1

                    prev_timestamp = timestamp
                    tmp_rtc_alarm, tmp_rtc_walarm = self.count_rtc_alarm(prev_timestamp, prev_alarm_timestamp, event);
                    walarm_rtc_count += tmp_rtc_walarm
                    alarm_rtc_count += tmp_rtc_alarm

                tmp_rtc_alarm, tmp_rtc_walarm = self.count_rtc_alarm(prev_timestamp, prev_alarm_timestamp, event);
                walarm_rtc_count += tmp_rtc_walarm
                alarm_rtc_count += tmp_rtc_alarm

            if wakeup_content_flag:
                self.count_wifi_ap(line)
                # 统计App wakeup alarm
                # if "Wakeup alarm *walarm*:" in line:
                # 根据apk名称统计
                app_name_pattern = re.search(r'Apk\s(.+?):', line)
                if app_name_pattern:
                    if app_wakeup_num != 0:
                        app_wakeup[app_name] = attri_num
                    app_wakeup_num = 0
                    app_name = app_name_pattern.group(1)
                s_app_wakeup = re.search(r'Wakeup alarm \*walarm\*:(.+?):\s(\d+)\s+times', line)
                if s_app_wakeup:
                    attri = s_app_wakeup.group((1))
                    attri_num = int(s_app_wakeup.group((2)))
                    app_wakeup_alarm_num += attri_num
                    app_wakeup_num += attri_num
            if wakeup_content_out_flag:
                if app_wakeup_num != 0:
                    app_wakeup[app_name] = attri_num
                break
                # TODO:统计不同应用的waekup alarm，找到与qpnp_rtc_alarm关系最大的那个

        # 增加属性
        app_wakeup["wakeup_alarm"] = app_wakeup_alarm_num
        app_wakeup["qpnp_rtc_alarm"] = qpnp_rtc_alarm

        if charge_end == None:
            charge_end = charge
            charge_end_time = time
        total_hour = (charge_end_time - charge_start_time) / (60 * 60 * 1000)
        total_drain = charge_start - charge_end
        self.averageDrain = total_drain / total_hour
        self.wakeupRtcAlarm = walarm_rtc_count + alarm_rtc_count
        self.deliveryRtcAlarm = w_count + a_count
        self.qpnpRtcAlarm = qpnp_rtc_alarm
        self.testTime = total_hour;

    # 耗电相关指标
    def print_drain(self):
        # print("test duration:" + duration)
        print("average drain:" + f"{self.averageDrain:.2f}")
        print("qpnp_rtc_alarm:" + f"{self.qpnpRtcAlarm / self.testTime:.2f}" + "(count/hr)")
        # print("actual drain:" + f"{actual_drain:.2f}")
        print(
            "walarm&rtc_alarm Count+alarm&rtc_alarm Count:" + f"{self.wakeupRtcAlarm / self.testTime:.2f}" + "(count/hr)")
        print("alarm Count + walarm Count:" + f"{self.deliveryRtcAlarm / self.testTime:.2f}" + "(count/hr)")
        print("test time:" + str(self.testTime) + "h" + "\n")

    # 打印输出硬件相关指标
    def print_hardware(self):
        print("CPU Count(Times):" + f"{self.cpu_count:.2f}")
        print("CPU Runtime:" + f"{self.cpu_runtime.total_seconds():.2f}")
        print("WIFI radio(Times):" + f"{self.radio_count / self.testTime:.2f}")
        print("WLAN_CE_2: " + f"{self.wlan_ce_2:.2f}")
        print("Wifi AP wakeup:" + f"{self.WIFI_AP_WAKUP / self.testTime:.2f}")
        print("Hardware Count:" + f"{self.hardware_wakeup / self.testTime:.2f}")
        print("Wakeup reason:" + f"{self.wakeup_reason / self.testTime:.2f}" + "\n")

    # 输出csv文件
    def wlan_to_csv(self):
        self.package_wlan_List = self.package_wlan_List.replace(0, np.nan)
        # 使用 dropna 方法删除包含NaN的行
        self.package_wlan_List = self.package_wlan_List.dropna()
        self.package_wlan_List.to_csv(os.path.join(self.output_wlan_path, self.file_name + ".csv"), index=False)

    def to_csv(self):
        pass

    def get_metrix(self, str):
        if str == "drain":
            return self.averageDrain,
        if str == "rtcAlarm":
            return self.qpnpRtcAlarm,
        if str == "wlan":
            return self.wlan_ce_2,
        if str == "wakeup_reason":
            return self.wakeup_reason,
        if str == "cpu_runtime":
            return self.cpu_runtime
        return 0
